//
///////////////////////////////////////////////////////
//外部实时钟芯片DS1337程序
//
//设备地址固定为 1101000X（X=0写，X=1读）， 数据按BCD码存储
//寄存器00 ： 秒(0x00~0x59)   ———— bit7是时钟允许位：0=工作，1=停止
//寄存器01 ： 分(0x00~0x59)
//寄存器02 ： 时(0x00~0x23)   ———— bit6是模式：0=24制，1=12制; bit5：0为AM，1为PM;
//寄存器03 ： 星期(0x01~0x07)
//寄存器04 ： 日(0x01~0x31)
//寄存器05 ： 月(0x01~0x12)
//寄存器06 ： 年(0x00~0x99)
//
//寄存器0E ： /EOSC 0 0 RS2 RS1 INTCN A2IE A1IE ———— /EOSC是振荡器使能（0使能）、INTCN是中断控制（0-INTA中断、SQW方波）、IE（0不使能）
//寄存器0F ：  OSF  0 0 0   0   0     A2F  A1F  ———— OSF=1表示停止
//
//电源VCC范围1.8V~5.5V
///////////////////////////////////////////////////////
//外部实时钟芯片PCF8563程序
//
//设备地址固定为 1010001X（X=0写，X=1读）， 数据按BCD码存储
//寄存器02 ： 秒(0x00~0x59)   ———— bit7是VL位：0=时钟信息有效，1=时钟信息不可靠
//寄存器03 ： 分(0x00~0x59)
//寄存器04 ： 时(0x00~0x23)   ———— 24制
//寄存器05 ： 日(0x01~0x31)
//寄存器06 ： 星期(0x00~0x06) ———— 0=星期天
//寄存器07 ： 月(0x01~0x12)
//寄存器08 ： 年(0x00~0x99)
//
//寄存器00 ： TEST1  0  STOP   0    TESTC  0    0    0   ———— TEST=0, STOP=0(=1停住RTC), TESTC=0
//寄存器01 ：   0    0    0  TI/TP   AF    TF  AIE  TIE  ———— TI/TP=0使能INT(=1脉冲), IE=0报警无效(=1有效)
//寄存器0D ：  FE    -    -    -     -     -   FD1  FD0  ———— LKOUT：FE=0高电平(=1有效)
//寄存器0E ：  TE    -    -    -     -     -   TD1  TD0  ———— TE=0关闭减计数器(=1启用)
//
//电源VCC范围1V~5.5V
///////////////////////////////////////////////////////
//口线空闲时为高电平，此时芯片进人低功耗模式
//	开始信号：clock保持H，data从H到L；
//	停止信号：clock保持H，data从L到H；
//	数据传输：clock高电平是保持稳定，低电平是改变；  MSB
//

#include "ds1307.h"
#include "format.h"
#include "main.h"

//ds1307的控制脚定义
#define TS_SCL_1	DS1307_SCL_H()
#define TS_SCL_0	DS1307_SCL_L()
#define TS_SDA_1	DS1307_SDA_H()
#define TS_SDA_0	DS1307_SDA_L()
#define delay()		delay_us(100)

u8	nowtime[7];			//DS1307的寄存器时间
u32 m_rtc_timer_sec;	//秒数表示的时间，DS1307转换
CurrentDateTimes  device_time;	//日历：设备结构体的时间
//月的天数
const u8 MaxDayArray[12]={31,28,31,30,31,30,31,31,30,31,30,31};

void start(void)  //开始信号
{	
	TS_SCL_0;
	delay();
	TS_SDA_1;
	delay();
	TS_SCL_1;
	delay();
	TS_SDA_0;
	delay();
	TS_SCL_0;
}
void stop(void)   //停止
{
	TS_SDA_0;
	delay();
	TS_SCL_1;
	delay();
	TS_SDA_1;
	delay();
	TS_SCL_0;
	delay();
	TS_SCL_1;
	delay();
}
void respons(void)  //芯片应答
{
	GPIO_InitTypeDef GPIO_InitStructure;
	u8 i = 0;
	
	TS_SCL_0;
	//DIO设置为输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	//上拉输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	//
	delay();
	TS_SCL_1;
	delay();
	while((DS1307_SDA_Read() ==  0)&&(i<200))i++;
	TS_SCL_0;
	//DIO设置为输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	//
}
void acknow(u8 mc)  //单片机应答: 0 或 1
{
	TS_SCL_0;
	delay();
	if(mc == 0)
		TS_SDA_0;
	else	
		TS_SDA_1;
	delay();
	TS_SCL_1;
	delay();
	TS_SCL_0;
}

//IIC写入1Byte数据
void ByteWrite(u8 _data) 
{ 
	u8 i;
	
	TS_SCL_0;
	delay();
    for(i=8; i>0; i--)
    {
		if(_data&0x80)
			TS_SDA_1;
		else
			TS_SDA_0;
		_data <<= 1;
		delay();
        TS_SCL_1;
		delay();
        TS_SCL_0;
		delay();
    }
}
//IIC读取1Byte数据
u8 ByteRead(void) 
{ 
	GPIO_InitTypeDef GPIO_InitStructure;
	u8 i, temp=0;
	
	TS_SCL_0;
	//DIO设置为输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	//上拉输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	//
	for(i=8; i>0; i--)
	{
		TS_SCL_0;
		delay();
		TS_SCL_1;
		delay();
		temp <<= 1;
		if(DS1307_SDA_Read() == 0)
			temp &= ~0x01;
		else
			temp |= 0x01;
		delay();
	}
	TS_SCL_0;
	//DIO设置为输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	//
    return(temp); 
}

//往ds1307寄存器写入数据（1字节）
void ds1307_Byte_Write(u8 adr, u8 _data)
{
    start();
    ByteWrite(RTC_ID);       //总线地址：写
    respons();
	ByteWrite(adr);		   //内部寄存器地址
	respons();
	ByteWrite(_data);      //数据
    respons();
	stop();
} 
//读取ds1307寄存器的数据（1字节）
u8 ds1307_Byte_Read(u8 adr)
{
    u8 _data;
	
	start();
    ByteWrite(RTC_ID);       //总线地址：写
    respons();
	ByteWrite(adr);		   //内部寄存器地址
	respons();
	//stop();
	
    start();
    ByteWrite(RTC_ID+1);         //总线地址：读
    respons();
	_data = ByteRead();      //读1Byte数据
	acknow(1);
	stop();
    return(_data);
}

//设置时间：秒、分、时、星期、日、月、年
void ds1307_SetTime(u8 *buf) 
{
    u8 i;
	u8 tmp[7];
	
#ifdef RTC_PCF8563
	//pcf8563时间存储不同，需要转换位置
	tmp[0] = buf[0];
	tmp[1] = buf[1];
	tmp[2] = buf[2];
	tmp[3] = buf[4];
	tmp[4] = buf[3];
	tmp[5] = buf[5];
	tmp[6] = buf[6];
#else
	tmp[0] = buf[0];
	tmp[1] = buf[1];
	tmp[2] = buf[2];
	tmp[3] = buf[3];
	tmp[4] = buf[4];
	tmp[5] = buf[5];
	tmp[6] = buf[6];
#endif
	
	start();
    ByteWrite(RTC_ID);       	//总线地址：写
    respons();
#ifdef RTC_PCF8563
	ByteWrite(0x02);		//内部寄存器地址
#else
	ByteWrite(0x00);		//内部寄存器地址
#endif
	respons();
	for(i=0; i<7; i++)   	//数据
	{
		ByteWrite(tmp[i]);
		respons();
	}
	stop();
}

//读取时间：秒、分、时、星期、日、月、年
void ds1307_GetTime(u8 *buf) 
{
    u8 i;
	u8 tmp[7];
	
	start();
    ByteWrite(RTC_ID);       	//总线地址：写
    respons();
#ifdef RTC_PCF8563
	ByteWrite(0x02);		//内部寄存器地址
#else
	ByteWrite(0x00);		//内部寄存器地址
#endif
	respons();
	//stop();
	
	start();
	ByteWrite(RTC_ID+1);         //总线地址：读
    respons();
	for(i=0; i<6; i++)   	//数据
	{
		tmp[i] = ByteRead();
		acknow(0);
	}
	tmp[6] = ByteRead();
	acknow(1);
	stop();
	
#ifdef RTC_PCF8563
	//pcf8563时间存储不同，需要转换位置
	buf[0] = tmp[0];
	buf[1] = tmp[1];
	buf[2] = tmp[2];
	buf[3] = tmp[4];
	buf[4] = tmp[3];
	buf[5] = tmp[5];
	buf[6] = tmp[6];
#else
	buf[0] = tmp[0];
	buf[1] = tmp[1];
	buf[2] = tmp[2];
	buf[3] = tmp[3];
	buf[4] = tmp[4];
	buf[5] = tmp[5];
	buf[6] = tmp[6];
#endif
}
//读取当前时间：4字节格式、结构体格式
void ReadTime_Now(void)
{
	uint16_t i;
	u32 TimeVar;
	
	//秒、分、时、日、星期、月、年
	ds1307_GetTime(nowtime);
	#if DEBUG > 10
		//打印读到的时间输出
		printf("time=%d/%d/%d,%d:%d:%d,%d\r\n", nowtime[6], nowtime[5], nowtime[4], nowtime[2], nowtime[1], nowtime[0], nowtime[3]);
	#endif
	//-------------------------------------------------------------------------
	device_time.tm_year = 2000+(nowtime[6]>>4)*10+(nowtime[6]&0x0F);
	device_time.tm_mon = ((nowtime[5]&0x10)>>4)*10+(nowtime[5]&0x0F);
	device_time.tm_day = ((nowtime[4]&0x30)>>4)*10+(nowtime[4]&0x0F);
	device_time.tm_week = (nowtime[3]&0x07);
	device_time.tm_hour = ((nowtime[2]&0x30)>>4)*10+(nowtime[2]&0x0F);
	device_time.tm_min = ((nowtime[1]&0x70)>>4)*10+(nowtime[1]&0x0F);
	device_time.tm_sec = ((nowtime[0]&0x70)>>4)*10+(nowtime[0]&0x0F);
	//-------------------------------------------------------------------------
	
	TimeVar = 0;
	for(i=2000;i<device_time.tm_year;i++)
	{//年
		if( ((i%400)==0) || (((i%4)==0)&&((i%100)!=0)) )
		{//闰年=366天=366*24*60*60
			TimeVar += 366*24*60*60;	//366*86400
		}
		else
		{
			TimeVar += 365*24*60*60;	//365*86400
		}
	}
	if(device_time.tm_mon > 0)
	{//月
		for(i=0;i<device_time.tm_mon-1;i++)
		{
			TimeVar += MaxDayArray[i]*24*60*60;
		}
		if( (((device_time.tm_year%400)==0) || (((device_time.tm_year%4)==0)&&((device_time.tm_year%100)!=0))) && (device_time.tm_mon > 2) )
		{
			TimeVar += 24*60*60;
		}
	}
	if(device_time.tm_day > 0)
	{//日
		TimeVar += (device_time.tm_day-1)*24*60*60;
	}
	//当天
	TimeVar += device_time.tm_hour*60*60 + device_time.tm_min*60 + device_time.tm_sec;
	m_rtc_timer_sec = TimeVar;
	#if DEBUG > 10
		//打印读到的时间输出
		printf("time=%d\r\n", m_rtc_timer_sec);
	#endif
	//-------------------------------------------------------------------------
}

u8 ds1307_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//口线设置
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	TS_SDA_1;
	TS_SCL_1;
	//查看时序输出
#ifdef RTC_PCF8563
	if(ds1307_Byte_Read(0x00)!=0x00)
	{
		ds1307_Byte_Write(0x00, 0x00);	//不要输出方波，降低功耗
		ds1307_Byte_Write(0x01, 0x00);	//不要输出方波，降低功耗
		ds1307_Byte_Write(0x0D, 0x00);	//不要输出方波，降低功耗
		ds1307_Byte_Write(0x0E, 0x00);	//不要输出方波，降低功耗
	}
#else
	if((ds1307_Byte_Read(0x07)&0x10)==0x10)
	{
		ds1307_Byte_Write(0x07, 0x80);	//不要输出方波，降低功耗
	}
#endif
	//查看时间：秒、分、时、星期、日、月、年
	ReadTime_Now();
	if( (nowtime[0]==0xFF)&&(nowtime[1]==0xFF)&&(nowtime[2]==0xFF)&&(nowtime[3]==0xFF)&&
	    (nowtime[4]==0xFF)&&(nowtime[5]==0xFF)&&(nowtime[6]==0xFF) )
	{ //DS1307读取失败
		BuzzerOn;			//蜂鸣器长鸣，重启
		while(1);				//等看门狗复位
	}
	else if( (device_time.tm_mon > 12)||(device_time.tm_mon == 0) || 
			 (device_time.tm_day > 31)||(device_time.tm_day == 0) || 
			 (device_time.tm_hour > 24)||(device_time.tm_min > 60)||
			 (device_time.tm_sec > 60)||(device_time.tm_year > 2099) )
	{ //时间数据出错：恢复为2000年1月1日0点0分0秒，周六
		nowtime[6] = 0x00;
		nowtime[5] = 0x01;
		nowtime[4] = 0x01;
		nowtime[3] = 0x06;
		nowtime[2] = 0x00;
		nowtime[1] = 0x00;
		nowtime[0] = 0x00;
		ds1307_SetTime(nowtime);
		return 1;
	}
	else
	{
	#ifndef RTC_PCF8563
		if((nowtime[2]&0x40)==0x40)
		{ //需要是24制
			nowtime[2] &= ~0x40;
			ds1307_Byte_Write(0x02, nowtime[2]);
		}
		if((nowtime[0]&0x80)==0x80)
		{ //需要允许时钟运行
			nowtime[0] &= ~0x80;
			ds1307_Byte_Write(0x00, nowtime[0]);
			return 1;
		}
	#else
		if((nowtime[0]&0x80)==0x80)
		{ //需要允许时钟运行
			nowtime[0] &= ~0x80;
			ds1307_Byte_Write(0x02, nowtime[0]);
			return 1;
		}
	#endif
	}
	
	#if DEBUG > 0
		printf("now=%d/%d/%d ", device_time.tm_year, device_time.tm_mon, device_time.tm_day);
		printf("%d:%d:%d \r\n", device_time.tm_hour, device_time.tm_min, device_time.tm_sec);
	#endif
	return 0;
}

//////////////////////////////////////////////////////////////////////
